package gov.nasa.jpf.symbc.modelcounter.sampler;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * An {@link Assignment} that uses a {@link HashMap} to store the variable-value
 * mappings and a {@link Random} to fill in the missing values.
 */
public class MapAssignment implements Assignment {

	/**
	 * The representation of the assignment as a mapping from integers (unique
	 * identifiers for symbolic variables) to objects.
	 */
	private Map<Integer, Object> mapping;

	/**
	 * The sampler to which this assignment belongs.
	 */
	private Sampler sampler;

	/**
	 * Constructor for a map-based assignment.
	 */
	public MapAssignment(Sampler sampler) {
		mapping = new HashMap<Integer, Object>();
		this.sampler = sampler;
	}

	/**
	 * Return the integer value of the variable mapped to the given identifier.
	 * 
	 * @param id the identifier of the variable
	 * @return the current integer value of the identifier in the map assignment
	 */
	private int getInt(int id) {
		if (mapping.containsKey(id)) {
			return (Integer) mapping.get(id);
		} else {
			int x = sampler.getRandomInt();
			mapping.put(id, x);
			return x;
		}
	}

	/* (non-Javadoc)
	 * @see gov.nasa.jpf.symbc.modelcounter.sampler.Assignment#getInt(java.lang.String, int)
	 */
	@Override
	public int getInt(String name) {
		return getInt(sampler.getVariableId(name));
	}

	/**
	 * Return the real value of the variable mapped to the given identifier.
	 * 
	 * @param id the identifier of the variable
	 * @return the current real value of the identifier in the map assignment
	 */
	private double getDouble(int id) {
		if (mapping.containsKey(id)) {
			return (Double) mapping.get(id);
		} else {
			double x = sampler.getRandomDouble();
			mapping.put(id, x);
			return x;
		}
	}

	/* (non-Javadoc)
	 * @see gov.nasa.jpf.symbc.modelcounter.sampler.Assignment#getDouble(java.lang.String, int)
	 */
	@Override
	public double getDouble(String name) {
		return getDouble(sampler.getVariableId(name));
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuffer b = new StringBuffer();
		for (Map.Entry<Integer, Object> e : mapping.entrySet()) {
			b.append((Integer) e.getKey());
			b.append('=');
			b.append(e.getValue());
			b.append(' ');
		}
		return b.toString();
	}

}
